#ifndef _MODULE_HPP
#define _MODULE_HPP

#include <cstdint>
#include <cstddef>
#include <istream>
#include <ostream>
#include <winstl/synch/thread_mutex.hpp>
#include <winstl/synch/spin_mutex.hpp>
#include <winstl/filesystem/path.hpp>
#include "process_monitor.hpp"
#include "watchdog.hpp"
#include "timer_queue.hpp"
#include "thread_pool.hpp"

namespace judge {

class module {
public:
	module();
	~module();

	unsigned processor_count();
	std::uint64_t tick_count();
	std::uint64_t idle_time();

private:
	// non-copyable
	module(const module &);
	module &operator=(const module &);

private:
	unsigned processor_count_;
	ULARGE_INTEGER tick_count_prev_;
	winstl::spin_mutex tick_count_mutex_;

public:
	winstl::thread_mutex inherit_handle_mutex;
	judge::process_monitor process_monitor;
	judge::watchdog watchdog;
	judge::timer_queue timer_queue;
	judge::thread_pool thread_pool;

private:
	unsigned _processor_count();
};

extern module mod;

template <std::size_t buffer_size>
bool stream_copy(std::istream &in, std::ostream &out)
{
	char buffer[buffer_size];

	while (!in.eof()) {
		in.read(buffer, sizeof(buffer));
		if (in.bad()) return false;
		out.write(buffer, in.gcount());
		if (out.fail()) return false;
	}

	return true;
}

template <std::size_t buffer_size>
bool stream_copy_n(std::istream &in, std::ostream &out, std::size_t max_size)
{
	char buffer[buffer_size];
	std::size_t size;

	while (max_size && !in.eof()) {
		size = std::min(sizeof(buffer), max_size);
		in.read(buffer, size);
		if (in.bad()) return false;
		size = static_cast<std::size_t>(in.gcount());
		out.write(buffer, size);
		if (out.fail()) return false;
		max_size -= size;
	}

	return true;
}

extern bool file_copy(const winstl::path_a &in_path, const winstl::path_a &out_path);

}

#endif
